
package com.taotao.enums.utils;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ClassUtils;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


@Slf4j
public class StringUtil {
    private static final int NOT_FOUND = -1;

    private StringUtil() {
    }


    /**
     * <p>Checks if CharSequence contains a search character, handling {@code null}.
     * This method uses {@link String#indexOf(int)} if possible.</p>
     *
     * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p>
     *
     * <pre>
     * StringUtils.contains(null, *)    = false
     * StringUtils.contains("", *)      = false
     * StringUtils.contains("abc", 'a') = true
     * StringUtils.contains("abc", 'z') = false
     * </pre>
     *
     * @param seq        the CharSequence to check, may be null
     * @param searchChar the character to find
     * @return true if the CharSequence contains the search character,
     * false if not or {@code null} string input
     * @since 2.0
     * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
     */
    public static boolean contains(final CharSequence seq, final int searchChar) {
        if (isEmpty(seq)) {
            return false;
        }
        return indexOf(seq, searchChar, 0) >= 0;
    }

    /**
     * Returns the index within {@code cs} of the first occurrence of the
     * specified character, starting the search at the specified index.
     * <p>
     * If a character with value {@code searchChar} occurs in the
     * character sequence represented by the {@code cs}
     * object at an index no smaller than {@code start}, then
     * the index of the first such occurrence is returned. For values
     * of {@code searchChar} in the range from 0 to 0xFFFF (inclusive),
     * this is the smallest value <i>k</i> such that:
     * <blockquote><pre>
     * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= start)
     * </pre></blockquote>
     * is true. For other values of {@code searchChar}, it is the
     * smallest value <i>k</i> such that:
     * <blockquote><pre>
     * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= start)
     * </pre></blockquote>
     * is true. In either case, if no such character occurs inm {@code cs}
     * at or after position {@code start}, then
     * {@code -1} is returned.
     *
     * <p>
     * There is no restriction on the value of {@code start}. If it
     * is negative, it has the same effect as if it were zero: the entire
     * {@code CharSequence} may be searched. If it is greater than
     * the length of {@code cs}, it has the same effect as if it were
     * equal to the length of {@code cs}: {@code -1} is returned.
     *
     * <p>All indices are specified in {@code char} values
     * (Unicode code units).
     *
     * @param cs         the {@code CharSequence} to be processed, not null
     * @param searchChar the char to be searched for
     * @param start      the start index, negative starts at the string start
     * @return the index where the search char was found, -1 if not found
     * @since 3.6 updated to behave more like {@code String}
     */
    static int indexOf(final CharSequence cs, final int searchChar, int start) {
        if (cs instanceof String) {
            return ((String) cs).indexOf(searchChar, start);
        }
        final int sz = cs.length();
        if (start < 0) {
            start = 0;
        }
        if (searchChar < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
            for (int i = start; i < sz; i++) {
                if (cs.charAt(i) == searchChar) {
                    return i;
                }
            }
            return NOT_FOUND;
        }
        //supplementary characters (LANG1300)
        if (searchChar <= Character.MAX_CODE_POINT) {
            final char[] chars = Character.toChars(searchChar);
            for (int i = start; i < sz - 1; i++) {
                final char high = cs.charAt(i);
                final char low = cs.charAt(i + 1);
                if (high == chars[0] && low == chars[1]) {
                    return i;
                }
            }
        }
        return NOT_FOUND;
    }

    /**
     * 第一个字符转换为小写
     *
     * @param string
     */
    public static String firstCharToLowerCase(String string) {
        char firstChar = string.charAt(0);
        if (firstChar >= 'A' && firstChar <= 'Z') {
            char[] arr = string.toCharArray();
            arr[0] += ('a' - 'A');
            return new String(arr);
        }
        return string;
    }


    /**
     * 第一个字符转换为大写
     *
     * @param string
     */
    public static String firstCharToUpperCase(String string) {
        char firstChar = string.charAt(0);
        if (firstChar >= 'a' && firstChar <= 'z') {
            char[] arr = string.toCharArray();
            arr[0] -= ('a' - 'A');
            return new String(arr);
        }
        return string;
    }


    /**
     * 驼峰转下划线格式
     *
     * @param string
     */
    public static String camelToUnderline(String string) {
        if (isBlank(string)) {
            return "";
        }
        int strLen = string.length();
        StringBuilder sb = new StringBuilder(strLen);
        for (int i = 0; i < strLen; i++) {
            char c = string.charAt(i);
            if (Character.isUpperCase(c) && i > 0) {
                sb.append('_');
            }
            sb.append(Character.toLowerCase(c));
        }
        return sb.toString();
    }

    /**
     * 下划线转驼峰格式
     *
     * @param string
     */
    public static String underlineToCamel(String string) {
        if (isBlank(string)) {
            return "";
        }
        String temp = string.toLowerCase();
        int strLen = temp.length();
        StringBuilder sb = new StringBuilder(strLen);
        for (int i = 0; i < strLen; i++) {
            char c = temp.charAt(i);
            if (c == '_') {
                if (++i < strLen) {
                    sb.append(Character.toUpperCase(temp.charAt(i)));
                }
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * Gets a CharSequence length or {@code 0} if the CharSequence is
     * {@code null}.
     *
     * @param cs a CharSequence or {@code null}
     * @return CharSequence length or {@code 0} if the CharSequence is
     * {@code null}.
     * @since 2.4
     * @since 3.0 Changed signature from length(String) to length(CharSequence)
     */
    public static int length(final CharSequence cs) {
        return cs == null ? 0 : cs.length();
    }


    /**
     * <p>Checks if a CharSequence is empty (""), null or whitespace only.</p>
     *
     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
     *
     * <pre>
     * StringUtils.isBlank(null)      = true
     * StringUtils.isBlank("")        = true
     * StringUtils.isBlank(" ")       = true
     * StringUtils.isBlank("bob")     = false
     * StringUtils.isBlank("  bob  ") = false
     * </pre>
     *
     * @param cs the CharSequence to check, may be null
     * @return {@code true} if the CharSequence is null, empty or whitespace only
     * @since 2.0
     * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
     */
    public static boolean isBlank(final CharSequence cs) {
        final int strLen = length(cs);
        if (strLen == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if (!Character.isWhitespace(cs.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    // Empty checks
    //-----------------------------------------------------------------------

    /**
     * <p>Checks if a CharSequence is empty ("") or null.</p>
     *
     * <pre>
     * StringUtils.isEmpty(null)      = true
     * StringUtils.isEmpty("")        = true
     * StringUtils.isEmpty(" ")       = false
     * StringUtils.isEmpty("bob")     = false
     * StringUtils.isEmpty("  bob  ") = false
     * </pre>
     *
     * <p>NOTE: This method changed in Lang version 2.0.
     * It no longer trims the CharSequence.
     * That functionality is available in isBlank().</p>
     *
     * @param cs the CharSequence to check, may be null
     * @return {@code true} if the CharSequence is empty or null
     * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
     */
    public static boolean isEmpty(final CharSequence cs) {
        return cs == null || cs.length() == 0;
    }

    public static boolean isAnyBlank(String... strings) {
        if (strings == null || strings.length == 0) {
            throw new IllegalArgumentException("args is empty.");
        }

        for (String str : strings) {
            if (isBlank(str)) {
                return true;
            }
        }
        return false;
    }


    public static boolean isNotBlank(String str) {
        return !isBlank(str);
    }


    public static boolean areNotBlank(String... strings) {
        return !isAnyBlank();
    }


    /**
     * 这个字符串是否是全是数字
     *
     * @param str
     * @return
     */
    public static boolean isNumeric(String str) {
        if (isBlank(str)) {
            return false;
        }
        for (int i = str.length(); --i >= 0; ) {
            int chr = str.charAt(i);
            if (chr < 48 || chr > 57) {
                return false;
            }
        }
        return true;
    }


    public static boolean startsWithAny(String str, String... prefixes) {
        if (isBlank(str) || prefixes == null || prefixes.length == 0) {
            return false;
        }

        for (String prefix : prefixes) {
            if (str.startsWith(prefix)) {
                return true;
            }
        }
        return false;
    }


    public static boolean endsWithAny(String str, String... suffixes) {
        if (isBlank(str) || suffixes == null || suffixes.length == 0) {
            return false;
        }

        for (String suffix : suffixes) {
            if (str.endsWith(suffix)) {
                return true;
            }
        }
        return false;
    }


    public static String trimOrNull(String string) {
        return string != null ? string.trim() : null;
    }


    /**
     * 正则匹配
     *
     * @param regex
     * @param input
     * @return
     */
    public static boolean matches(String regex, String input) {
        if (null == regex || null == input) {
            return false;
        }
        return Pattern.matches(regex, input);
    }

    /**
     * 合并字符串，优化 String.join() 方法
     *
     * @param delimiter
     * @param elements
     * @return 新拼接好的字符串
     * @see String#join(CharSequence, CharSequence...)
     */
    public static String join(String delimiter, CharSequence... elements) {
        if (CollectionUtils.isEmpty(elements)) {
            return "";
        } else if (elements.length == 1) {
            return String.valueOf(elements[0]);
        } else {
            return String.join(delimiter, elements);
        }
    }

    /**
     * 合并字符串，优化 String.join() 方法
     *
     * @param delimiter
     * @param elements
     * @return 新拼接好的字符串
     * @see String#join(CharSequence, CharSequence...)
     */
    public static String join(String delimiter, Collection<? extends CharSequence> elements) {
        if (CollectionUtils.isEmpty(elements)) {
            return "";
        } else if (elements.size() == 1) {
            return String.valueOf(elements.iterator().next());
        } else {
            return String.join(delimiter, elements);
        }
    }


    /**
     * 合并字符串，优化 String.join() 方法
     *
     * @param delimiter
     * @param objs
     * @param function
     * @param <T>
     */
    public static <T> String join(String delimiter, Collection<T> objs, Function<T, String> function) {
        if (CollectionUtils.isEmpty(objs)) {
            return "";
        } else if (objs.size() == 1) {
            T next = objs.iterator().next();
            return String.valueOf(function.apply(next));
        } else {
            String[] strings = new String[objs.size()];
            int index = 0;
            for (T obj : objs) {
                strings[index++] = function.apply(obj);
            }
            return String.join(delimiter, strings);
        }
    }


    public static String tryTrim(String string) {
        return string != null ? string.trim() : null;
    }


    /**
     * 将对象中空字符串属性设为null
     */
    public static void removeBlankStrField(Object o) {

        Class cls = o.getClass();

        while (cls != null && cls != Object.class) {
            Field[] fields = cls.getDeclaredFields();
            if (null != fields || fields.length > 0) {

                for (Field fd : fields) {
                    if (!Objects.equals(String.class, fd.getType())) {

                        if (!Modifier.isStatic(fd.getModifiers()) && !ClassUtils.isPrimitiveOrWrapper(fd.getType())) {
                            if (!fd.isAccessible()) {
                                fd.setAccessible(true);
                            }

                            try {
                                Object fv = fd.get(o);
                                if (null != fv) {
                                    removeBlankStrField(fv);
                                }

                            } catch (Exception e) {
                                log.error("", e);
                            }

                        }


                    } else {
                        if (!fd.isAccessible()) {
                            fd.setAccessible(true);
                        }

                        try {
                            String val = (String) fd.get(o);
                            if (null == val || val.trim().length() == 0) {
                                fd.set(o, null);
                            }
                        } catch (Exception e) {
                            log.error("", e);
                        }
                    }


                }
            }
            // 遍历父类属性
            cls = cls.getSuperclass();
        }


    }


    /**
     * 字符串比较大小
     *
     * @param str1
     * @param str2
     * @param asc
     * @return
     */
    public static int compile(String str1, String str2, boolean asc) {
        int len1 = str1.length();
        int len2 = str2.length();

        if (str1.equals(str2)) {//两者完全相等
            return 0;
        }

        //如果要按照升序排序,则o1 小于o2，返回-1（负数），相等返回0，01大于02返回1（正数）
        //如果要按照降序排序,则o1 小于o2，返回1（正数），相等返回0，01大于02返回-1（负数）
        String regx = "^(([-+]?\\d+)|(\\d+))(\\.)?(\\d+)";//判断是整型或者浮整型
        Pattern pattern = Pattern.compile(regx);

        if (pattern.matcher(str1).find() && pattern.matcher(str2).find()) {
            if (str1.indexOf(".") != -1 || str2.indexOf(".") != -1) {
                double d1 = Double.valueOf(str1);
                double d2 = Double.valueOf(str2);
                double df = d1 - d2;

                if (df > 0.00001) {
                    return asc ? 1 : -1;
                } else if (df < -0.00001) {
                    return asc ? -1 : 1;
                } else {
                    return 0;
                }
            } else {
                int i1 = Integer.valueOf(str1);
                int i2 = Integer.valueOf(str2);
                int df = i1 - i2;

                if (df > 0) {
                    return asc ? 1 : -1;
                } else if (df < 0) {
                    return asc ? -1 : 1;
                } else {
                    return 0;
                }
            }
        } else {
            //字符串比较
            int lf = len1 - len2;

            if (lf > 0) {
                return asc ? 1 : -1;
            } else if (lf < 0) {
                return asc ? -1 : 1;
            } else {
                //长度相同则需要逐一比较
                for (int i = 0; i < len1; i++) {
                    int af = str1.charAt(i) - str2.charAt(i);

                    if (af > 0) {
                        return asc ? 1 : -1;
                    } else if (af < 0) {
                        return asc ? -1 : 1;
                    } else {
                        continue;
                    }
                }
            }
        }

        return 0;
    }

    /**
     * 升序
     *
     * @param str
     * @return
     */
    public static String[] sortAsc(String[] str) {
        if (str == null || str.length == 1) {
            return str;
        }

        Arrays.sort(str, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return StringUtil.compile(o1.trim(), o2.trim(), true);
            }
        });

        return str;
    }

    /**
     * 降序
     *
     * @param str
     * @return
     */
    public static String[] sortDesc(String[] str) {
        if (str == null || str.length == 1) {
            return str;
        }

        Arrays.sort(str, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return StringUtil.compile(o1.trim(), o2.trim(), false);
            }
        });

        return str;
    }

    /**
     * 连号
     *
     * @param noStr
     * @param separator
     * @return
     */
    public static String chainNo(String noStr, String separator) {
        if (isEmpty(noStr)) {
            return noStr;
        }

        if (StringUtil.isBlank(separator)) {
            separator = ",";
        }

        String tmp = noStr.replace(" ", "");

        return chainNo(tmp.split(separator), separator);
    }

    /**
     * 编号累加
     *
     * @param str
     * @param opt
     * @return
     */
    public static String noAdd(String str, int opt) {
        String regx = "[1-9]+\\d*";//判断是整型或者浮整型
        Pattern pattern = Pattern.compile(regx);
        Matcher m = pattern.matcher(str);

        if (m.find()) {
            String old = m.group();
            int lold = old.length();
            String begin = str.substring(0, str.length() - lold);
            int num = Integer.valueOf(old);
            int cur = num + opt;
            int lnew = String.valueOf(cur).length();
            int lf = lnew - lold;

            if (cur < 0) {
                return null;
            }

            if (lf > 0) {//需要进位
                if (lf > begin.length()) {//不够进位
                    return null;
                }

                String ext = begin.substring(begin.length() - lf);
                for (int i = 0; i < ext.length(); i++) {
                    if (ext.charAt(i) != '0') {//只有全0才能进位
                        return null;
                    }
                }

                return begin.substring(0, begin.length() - lf) + cur;
            } else if (lf < 0) {//需要补0
                StringBuffer ext = new StringBuffer();
                for (int i = lf; i < 0; i++) {
                    ext.append("0");
                }

                return begin + ext + cur;
            } else {
                return begin + cur;
            }
        } else {
            if (opt > 0) {
                String num = String.valueOf(opt);

                if (num.length() <= str.length()) {
                    String ext = str.substring(str.length() - num.length(), str.length());
                    for (int i = 0; i < ext.length(); i++) {
                        if (ext.charAt(i) != '0') {//只有全0才能进位
                            return null;
                        }
                    }

                    return str.substring(0, str.length() - num.length()) + num;
                }
            }
        }

        return null;
    }

    /**
     * 连号
     *
     * @param noArray
     * @param separator
     * @return
     */
    public static String chainNo(String[] noArray, String separator) {
        StringBuffer bill = new StringBuffer();

        if (noArray.length == 1) {
            return noArray[0];
        } else {
            String[] tmp = sortAsc(noArray);//升序排列
            int ll = tmp.length;
            int i = 0;

            while (i < ll) {
                String cur = tmp[i];
                String next = noAdd(cur, 1);
                String end = null;
                int j = i + 1;

                if (j >= ll) {//i为最后一个
                    if (bill.length() > 0) {
                        bill.append(separator);
                    }

                    bill.append(cur);
                    break;
                }

                while (next != null && equals(next, tmp[j])) {
                    end = tmp[j];
                    next = noAdd(next, 1);
                    j++;

                    if (j >= ll) {//遍历完成
                        break;
                    }
                }

                if (bill.length() > 0) {
                    bill.append(separator);
                }

                if (end == null) {
                    bill.append(cur);
                } else {
                    bill.append(cur + "-" + end);
                }

                i = j;
            }

            return bill.toString();
        }
    }

    public static boolean isEmpty(byte[] bytes) {
        return bytes == null || bytes.length == 0;
    }

    /**
     * 全部都不为空
     *
     * @param css
     * @return
     */
    public static boolean isAllNoneEmpty(Object... css) {
        if (CollectionUtils.isEmpty(css)) {
            return false;
        } else {
            Object[] var1 = css;
            int var2 = css.length;
            for (int var3 = 0; var3 < var2; ++var3) {
                Object cs = var1[var3];

                if (cs instanceof CharSequence) {
                    if (isEmpty((CharSequence) cs)) {
                        return false;
                    }
                } else if (cs instanceof Collection<?>) {
                    if (((Collection<?>) cs).size() == 0) {
                        return false;
                    }
                } else if (cs instanceof Map<?, ?>) {
                    if (((Map<?, ?>) cs).size() == 0) {
                        return false;
                    }
                } else {
                    if (cs == null) {
                        return false;
                    }
                }
            }

            return true;
        }
    }

    /**
     * 全部都不为空
     *
     * @param css
     * @return
     */
    public static boolean isAllNoneBlank(Object... css) {
        if (CollectionUtils.isEmpty(css)) {
            return false;
        } else {
            Object[] var1 = css;
            int var2 = css.length;
            for (int var3 = 0; var3 < var2; ++var3) {
                Object cs = var1[var3];

                if (cs instanceof CharSequence) {
                    if (isBlank((CharSequence) cs)) {
                        return false;
                    }
                } else if (cs instanceof Collection<?>) {
                    if (((Collection<?>) cs).size() == 0) {
                        return false;
                    }
                } else if (cs instanceof Map<?, ?>) {
                    if (((Map<?, ?>) cs).size() == 0) {
                        return false;
                    }
                } else {
                    if (cs == null) {
                        return false;
                    }
                }
            }

            return true;
        }
    }

    public static String bytes2String(byte[] bytes) {
        if (bytes == null) {
            return null;
        }

        return new String(bytes);
    }

    public static String toString(Throwable throwable) {
        if (throwable == null) {
            return "Error: The throwable is null";
        }

        return getStackTrace(throwable);
    }

    public static String getStackTrace(final Throwable throwable) {
        final StringWriter sw = new StringWriter();
        final PrintWriter pw = new PrintWriter(sw, true);
        throwable.printStackTrace(pw);
        return sw.getBuffer().toString();
    }


    public static String toString(Map<?, ?> data) {
        if (data == null || data.size() == 0) {
            return "";
        }

        StringBuffer buffer = new StringBuffer();
        for (Map.Entry<?, ?> it : data.entrySet()) {
            if (buffer.length() == 0) {
                buffer.append("{");
            } else {
                buffer.append(", ");
            }
            buffer.append(it.getKey() + ": " + it.getValue());
        }

        if (buffer.length() == 0) {
            return "{}";
        } else {
            buffer.append("}");
            return buffer.toString();
        }
    }

    public static String toString(List<?> data) {
        StringBuffer buffer = new StringBuffer();
        for (Object obj : data) {
            if (buffer.length() > 0) {
                buffer.append(", ");
            }
            buffer.append(obj.toString());
        }

        return buffer.toString();
    }


    public static String toString(URL[] urls) {
        if (urls == null || urls.length == 0) {
            return "";
        }

        StringBuffer buf = new StringBuffer();

        for (URL url : urls) {
            buf.append(url.toString() + ";");
        }

        return buf.toString();
    }

    public static String toString(Integer i) {
        return i == null ? null : String.valueOf(i);
    }

    public static String toString(int i) {
        return String.valueOf(i);
    }

    public static String toString(char[] data) {
        return String.valueOf(data);
    }

    public static String toString(Boolean b) {
        return b == null ? null : String.valueOf(b);
    }

    public static String toString(boolean b) {
        return String.valueOf(b);
    }

    public static String toString(char c) {
        return String.valueOf(c);
    }

    public static String toString(Long l) {
        return l == null ? null : String.valueOf(l);
    }

    public static String toString(long l) {
        return String.valueOf(l);
    }

    public static String toString(Float f) {
        return f == null ? null : String.valueOf(f);
    }

    public static String toString(float f) {
        return String.valueOf(f);
    }

    public static String toString(Double d) {
        return d == null ? null : String.valueOf(d);
    }

    public static String toString(double d) {
        return String.valueOf(d);
    }

    public static String toString(BigDecimal b) {
        if (b == null) {
            return "0.00";
        }

        DecimalFormat df = new DecimalFormat("#.00");

        return df.format(b);
    }

    public static Long toLong(String cs) {
        try {
            return Long.valueOf(cs);
        } catch (NumberFormatException e) {
            return null;
        }
    }

    public static String[] splitByComma(String s) {
        return split(s, ',');
    }

    public static String[] splitByColon(String s) {
        if (isEmpty(s)) {
            return new String[0];
        }
        return split(s, ':');
    }

    public static String[] split(String s, char delimeter) {
        int end = s.length();
        List<String> res = new ArrayList<>();
        int start = 0;
        for (int i = 0; i < end; ++i) {
            if (s.charAt(i) == delimeter) {
                if (start == i) {
                    res.add("");
                } else {
                    res.add(s.substring(start, i));
                }
                start = i + 1;
            }
        }
        if (start == 0) {
            res.add(s);
        } else if (start != end) {
            res.add(s.substring(start, end));
        } else {
            for (int i = res.size() - 1; i >= 0 && res.get(i).isEmpty(); --i) {
                res.remove(i);
            }
        }
        return res.toArray(new String[res.size()]);
    }

    public static String floatToPercent(float f) {
        NumberFormat percentFormat = NumberFormat.getPercentInstance();
        percentFormat.setMaximumFractionDigits(1);
        return percentFormat.format(f);
    }

    public static String retainTwoDecimal(float f) {
        DecimalFormat decimalFormat = new DecimalFormat("#.00");
        return decimalFormat.format(f);
    }

    public static byte[] toFourBytes(int value) {
        return toBytes(value, 4);
    }

    public static byte[] toTwoBytes(int value) {
        return toBytes(value, 2);
    }

    public static byte[] toBytes(int value, int byteCount) {
        byte[] bytes = new byte[byteCount];
        int i = 0;
        int j = byteCount - 1;
        while (i < byteCount) {
            bytes[i] = (byte) (value >>> 8 * j & 0xFF);
            ++i;
            --j;
        }
        return bytes;
    }

    public static int toInt(byte[] bytes) {
        int value = 0;
        int i = 0;
        int j = bytes.length - 1;
        while (i < bytes.length) {
            value |= (bytes[i] & 0xFF) << 8 * j;
            ++i;
            --j;
        }
        return value;
    }

    public static boolean equals(char o, CharSequence t) {
        return equals(String.valueOf(o), t);
    }

    public static boolean equals(CharSequence t, char o) {
        return equals(t, String.valueOf(o));
    }

    public static boolean equals(Object o, Object t) {
        if (o == t) {
            return true;
        }

        if (o != null && t == null) {
            return false;
        }

        if (o == null && t != null) {
            return false;
        }

        return o.equals(t);
    }

    public static boolean equals(List<Object> o, List<Object> t) {
        if (o == t) {
            return true;
        }

        if (o != null && t == null) {
            return false;
        }

        if (o == null && t != null) {
            return false;
        }

        int len = o.size();
        if (len != t.size()) {
            return false;
        }

        for (int i = 0; i < len; i++) {
            if (!equals(o.get(i), t.get(i))) {
                return false;
            }
        }

        return true;
    }

    public static boolean equalsAll(CharSequence string, CharSequence... searchStrings) {
        if (!CollectionUtils.isEmpty(searchStrings)) {
            CharSequence[] var2 = searchStrings;
            int var3 = searchStrings.length;

            for (int var4 = 0; var4 < var3; ++var4) {
                CharSequence next = var2[var4];
                if (!equals(string, next)) {
                    return false;
                }
            }
        } else {
            return string == null ? true : false;
        }

        return true;
    }

    public static boolean equalsAllIgnoreCase(String string, String... searchStrings) {
        if (!CollectionUtils.isEmpty(searchStrings)) {
            String[] ses = searchStrings;
            int len = searchStrings.length;

            for (int i = 0; i < len; ++i) {
                String next = ses[i];
                if (!StringUtil.equalsIgnoreCase(string, next)) {
                    return false;
                }
            }
        } else {
            return string == null ? true : false;
        }

        return true;
    }

    private static boolean equalsIgnoreCase(String s, String next) {
        return s == null ? next == null : s.equalsIgnoreCase(next);


    }

    public static boolean isTrue(Object bl) {
        return isTrue(bl, false);
    }

    public static boolean isTrue(Object bl, boolean dftVal) {
        if (bl == null) {
            return dftVal;
        }

        if (bl instanceof Boolean) {
            return (Boolean) bl;
        }

        if (bl instanceof Number) {
            Number num = (Number) bl;
            return num.intValue() != 0;
        }

        if (bl instanceof String) {
            String str = (String) bl;

            return StringUtil.isNotBlank(str) && (!"0".equals(str) || StringUtil.equalsAllIgnoreCase(str, "y", "true"));
        }

        return false;
    }


    public static boolean isFalse(Object bl) {
        return isFalse(bl, false);
    }

    public static boolean isFalse(Object bl, boolean dftVal) {
        if (bl == null) {
            return dftVal;
        }

        if (bl instanceof Boolean) {
            return (Boolean) bl;
        }

        if (bl instanceof Number) {
            Number num = (Number) bl;
            return num.intValue() == 0;
        }

        if (bl instanceof String) {
            return StringUtil.equalsAllIgnoreCase((String) bl, "0", "n", "false");
        }

        return false;
    }

    public static boolean booleanEquals(Boolean first, Boolean second) {
        if (first == null && second == null) {
            return true;
        }

        if (first == null && second != null) {
            return false;
        }

        if (first != null && second == null) {
            return false;
        }

        return first.equals(second);
    }

    public static String format(String msg, Object... args) {
        if (isEmpty(msg)) {
            return msg;
        }

        return String.format(msg.replace("{}", "%s"), args);
    }

    public static String replaceRegex(String source, String regex, String replacement) {
        return RegExUtils.replacePattern(source, regex, replacement);
    }

    /**
     * str1第i位是否与str2相同
     *
     * @param str1
     * @param index
     * @param str2
     * @return
     */
    public static boolean equals(String str1, int index, String str2) {
        if (str1 == null || str1.length() == 0) {
            return false;
        }
        if (index < 0 || index > str1.length()) {
            return false;
        }
        if (str2 == null || str2.length() == 0) {
            return false;
        }
        return str1.charAt(index) == str2.charAt(0);
    }

    /**
     * 字符串是否存在
     *
     * @param str
     * @param array
     * @return
     */
    public static <T> boolean in(T str, T... array) {

        for (T s : array) {
            if (Objects.equals(s, str)) {
                return true;
            }
        }

        return false;
    }

    public static boolean inIgnoreCase(String str, String... array) {
        if (array == null) {
            return false;
        }
        for (String item : array) {
            if (str.equalsIgnoreCase(item)) {
                return true;
            }
        }
        return false;
    }


    private static Pattern BLANK_PATTERN = Pattern.compile("\\s*|\t|\r|\n");

    /**
     * 去掉字符串中的换行符，空格，制表符,回车
     *
     * @param str
     * @return
     */
    public static String replaceBlank(String str) {
        String dest = "";
        if (str != null) {
            Matcher m = BLANK_PATTERN.matcher(str);
            dest = m.replaceAll("");
        }
        return dest;
    }

    /**
     * 转为小写
     *
     * @param array
     * @return
     */
    public static String[] lowerCase(String[] array) {
        if (array == null) {
            return null;
        }
        String[] larray = new String[array.length];
        for (int i = 0; i < array.length; i++) {
            larray[i] = lowerCase(array[i]);
        }
        return array;
    }

    public static String lowerCase(final String str) {
        if (str == null) {
            return null;
        }
        return str.toLowerCase();
    }


    /**
     * 无此字符串
     *
     * @param str
     * @param array
     * @return
     */
    public static boolean notIn(String str, String... array) {
        return in(str, array) == false;
    }

    /**
     * 生成重复字符串
     *
     * @param s
     * @param times
     * @return
     */
    public static String[] repeatAsArray(String s, int times) {
        String[] arr = new String[times];
        for (int i = 0; i < times; i++) {
            arr[i] = s;
        }
        return arr;
    }

    public static String toHexString(byte[] data) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < data.length; i++) {
            String hex = Integer.toHexString(data[i] & 0xFF);
            hex = StringUtil.leftPad(hex, 2, "0");
            builder.append(hex);
        }
        return builder.toString();
    }


    /**
     * <p>The maximum size to which the padding constant(s) can expand.</p>
     */
    private static final int PAD_LIMIT = 8192;

    /**
     * <p>Returns padding using the specified delimiter repeated
     * to a given length.</p>
     *
     * <pre>
     * StringUtils.padding(0, 'e')  = ""
     * StringUtils.padding(3, 'e')  = "eee"
     * StringUtils.padding(-2, 'e') = IndexOutOfBoundsException
     * </pre>
     *
     * <p>Note: this method doesn't not support padding with
     * <a href="http://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
     * as they require a pair of <code>char</code>s to be represented.
     * </p>
     *
     * @param repeat  number of times to repeat delim
     * @param padChar character to repeat
     * @return String with repeated character
     * @throws IndexOutOfBoundsException if <code>repeat &lt; 0</code>
     */
    private static String padding(int repeat, char padChar) throws IndexOutOfBoundsException {
        if (repeat < 0) {
            throw new IndexOutOfBoundsException("Cannot pad a negative amount: " + repeat);
        }
        final char[] buf = new char[repeat];
        for (int i = 0; i < buf.length; i++) {
            buf[i] = padChar;
        }
        return new String(buf);
    }


    /**
     * <p>Left pad a String with spaces (' ').</p>
     *
     * <p>The String is padded to the size of <code>size</code>.</p>
     *
     * <pre>
     * StringUtils.leftPad(null, *)   = null
     * StringUtils.leftPad("", 3)     = "   "
     * StringUtils.leftPad("bat", 3)  = "bat"
     * StringUtils.leftPad("bat", 5)  = "  bat"
     * StringUtils.leftPad("bat", 1)  = "bat"
     * StringUtils.leftPad("bat", -1) = "bat"
     * </pre>
     *
     * @param str  the String to pad out, may be null
     * @param size the size to pad to
     * @return left padded String or original String if no padding is necessary,
     * <code>null</code> if null String input
     */
    public static String leftPad(String str, int size) {
        return leftPad(str, size, ' ');
    }

    /**
     * <p>Left pad a String with a specified character.</p>
     *
     * <p>Pad to a size of <code>size</code>.</p>
     *
     * <pre>
     * StringUtils.leftPad(null, *, *)     = null
     * StringUtils.leftPad("", 3, 'z')     = "zzz"
     * StringUtils.leftPad("bat", 3, 'z')  = "bat"
     * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
     * StringUtils.leftPad("bat", 1, 'z')  = "bat"
     * StringUtils.leftPad("bat", -1, 'z') = "bat"
     * </pre>
     *
     * @param str     the String to pad out, may be null
     * @param size    the size to pad to
     * @param padChar the character to pad with
     * @return left padded String or original String if no padding is necessary,
     * <code>null</code> if null String input
     * @since 2.0
     */
    public static String leftPad(String str, int size, char padChar) {
        if (str == null) {
            return null;
        }
        int pads = size - str.length();
        if (pads <= 0) {
            return str; // returns original String when possible
        }
        if (pads > PAD_LIMIT) {
            return leftPad(str, size, String.valueOf(padChar));
        }
        return padding(pads, padChar).concat(str);
    }

    /**
     * <p>Left pad a String with a specified String.</p>
     *
     * <p>Pad to a size of <code>size</code>.</p>
     *
     * <pre>
     * StringUtils.leftPad(null, *, *)      = null
     * StringUtils.leftPad("", 3, "z")      = "zzz"
     * StringUtils.leftPad("bat", 3, "yz")  = "bat"
     * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
     * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
     * StringUtils.leftPad("bat", 1, "yz")  = "bat"
     * StringUtils.leftPad("bat", -1, "yz") = "bat"
     * StringUtils.leftPad("bat", 5, null)  = "  bat"
     * StringUtils.leftPad("bat", 5, "")    = "  bat"
     * </pre>
     *
     * @param str    the String to pad out, may be null
     * @param size   the size to pad to
     * @param padStr the String to pad with, null or empty treated as single space
     * @return left padded String or original String if no padding is necessary,
     * <code>null</code> if null String input
     */
    public static String leftPad(String str, int size, String padStr) {
        if (str == null) {
            return null;
        }
        if (isEmpty(padStr)) {
            padStr = " ";
        }
        int padLen = padStr.length();
        int strLen = str.length();
        int pads = size - strLen;
        if (pads <= 0) {
            return str; // returns original String when possible
        }
        if (padLen == 1 && pads <= PAD_LIMIT) {
            return leftPad(str, size, padStr.charAt(0));
        }

        if (pads == padLen) {
            return padStr.concat(str);
        } else if (pads < padLen) {
            return padStr.substring(0, pads).concat(str);
        } else {
            char[] padding = new char[pads];
            char[] padChars = padStr.toCharArray();
            for (int i = 0; i < pads; i++) {
                padding[i] = padChars[i % padLen];
            }
            return new String(padding).concat(str);
        }
    }

    /**
     * <p>Right pad a String with spaces (' ').</p>
     *
     * <p>The String is padded to the size of <code>size</code>.</p>
     *
     * <pre>
     * StringUtils.rightPad(null, *)   = null
     * StringUtils.rightPad("", 3)     = "   "
     * StringUtils.rightPad("bat", 3)  = "bat"
     * StringUtils.rightPad("bat", 5)  = "bat  "
     * StringUtils.rightPad("bat", 1)  = "bat"
     * StringUtils.rightPad("bat", -1) = "bat"
     * </pre>
     *
     * @param str  the String to pad out, may be null
     * @param size the size to pad to
     * @return right padded String or original String if no padding is necessary,
     * <code>null</code> if null String input
     */
    public static String rightPad(String str, int size) {
        return rightPad(str, size, ' ');
    }

    /**
     * <p>Right pad a String with a specified character.</p>
     *
     * <p>The String is padded to the size of <code>size</code>.</p>
     *
     * <pre>
     * StringUtils.rightPad(null, *, *)     = null
     * StringUtils.rightPad("", 3, 'z')     = "zzz"
     * StringUtils.rightPad("bat", 3, 'z')  = "bat"
     * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
     * StringUtils.rightPad("bat", 1, 'z')  = "bat"
     * StringUtils.rightPad("bat", -1, 'z') = "bat"
     * </pre>
     *
     * @param str     the String to pad out, may be null
     * @param size    the size to pad to
     * @param padChar the character to pad with
     * @return right padded String or original String if no padding is necessary,
     * <code>null</code> if null String input
     * @since 2.0
     */
    public static String rightPad(String str, int size, char padChar) {
        if (str == null) {
            return null;
        }
        int pads = size - str.length();
        if (pads <= 0) {
            return str; // returns original String when possible
        }
        if (pads > PAD_LIMIT) {
            return rightPad(str, size, String.valueOf(padChar));
        }
        return str.concat(padding(pads, padChar));
    }

    /**
     * <p>Right pad a String with a specified String.</p>
     *
     * <p>The String is padded to the size of <code>size</code>.</p>
     *
     * <pre>
     * StringUtils.rightPad(null, *, *)      = null
     * StringUtils.rightPad("", 3, "z")      = "zzz"
     * StringUtils.rightPad("bat", 3, "yz")  = "bat"
     * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
     * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
     * StringUtils.rightPad("bat", 1, "yz")  = "bat"
     * StringUtils.rightPad("bat", -1, "yz") = "bat"
     * StringUtils.rightPad("bat", 5, null)  = "bat  "
     * StringUtils.rightPad("bat", 5, "")    = "bat  "
     * </pre>
     *
     * @param str    the String to pad out, may be null
     * @param size   the size to pad to
     * @param padStr the String to pad with, null or empty treated as single space
     * @return right padded String or original String if no padding is necessary,
     * <code>null</code> if null String input
     */
    public static String rightPad(String str, int size, String padStr) {
        if (str == null) {
            return null;
        }
        if (isEmpty(padStr)) {
            padStr = " ";
        }
        int padLen = padStr.length();
        int strLen = str.length();
        int pads = size - strLen;
        if (pads <= 0) {
            return str; // returns original String when possible
        }
        if (padLen == 1 && pads <= PAD_LIMIT) {
            return rightPad(str, size, padStr.charAt(0));
        }

        if (pads == padLen) {
            return str.concat(padStr);
        } else if (pads < padLen) {
            return str.concat(padStr.substring(0, pads));
        } else {
            char[] padding = new char[pads];
            char[] padChars = padStr.toCharArray();
            for (int i = 0; i < pads; i++) {
                padding[i] = padChars[i % padLen];
            }
            return str.concat(new String(padding));
        }
    }

    /**
     * 转为大写
     *
     * @param array
     * @return
     */
    public static String[] upperCase(String[] array) {
        if (array == null) {
            return null;
        }
        String[] uarray = new String[array.length];
        for (int i = 0; i < array.length; i++) {
            uarray[i] = upperCase(array[i]);
        }
        return array;
    }

    public static String upperCase(final String str) {
        if (str == null) {
            return null;
        }
        return str.toUpperCase();
    }

    public static String valueOf(Object obj) {
        return valueOf(obj, null);
    }

    /**
     * 转为字符串
     *
     * @param obj
     * @param defaultStr 为null或空字符串时的默认值
     * @return
     */
    public static String valueOf(Object obj, String defaultStr) {
        if (obj == null) {
            return defaultStr;
        }
        String val = obj.toString();
        return isEmpty(val) ? defaultStr : val;
    }

    // Substring
    //-----------------------------------------------------------------------
    /**
     * The empty String <code>""</code>.
     *
     * @since 2.0
     */
    public static final String EMPTY = "";

    /**
     * <p>Gets a substring from the specified String avoiding exceptions.</p>
     *
     * <p>A negative start position can be used to start <code>n</code>
     * characters from the end of the String.</p>
     *
     * <p>A <code>null</code> String will return <code>null</code>.
     * An empty ("") String will return "".</p>
     *
     * <pre>
     * StringUtils.substring(null, *)   = null
     * StringUtils.substring("", *)     = ""
     * StringUtils.substring("abc", 0)  = "abc"
     * StringUtils.substring("abc", 2)  = "c"
     * StringUtils.substring("abc", 4)  = ""
     * StringUtils.substring("abc", -2) = "bc"
     * StringUtils.substring("abc", -4) = "abc"
     * </pre>
     *
     * @param str   the String to get the substring from, may be null
     * @param start the position to start from, negative means
     *              count back from the end of the String by this many characters
     * @return substring from start position, <code>null</code> if null String input
     */
    public static String substring(String str, int start) {
        if (str == null) {
            return null;
        }

        // handle negatives, which means last n characters
        if (start < 0) {
            start = str.length() + start; // remember start is negative
        }

        if (start < 0) {
            start = 0;
        }
        if (start > str.length()) {
            return EMPTY;
        }

        return str.substring(start);
    }

    /**
     * <p>Gets a substring from the specified String avoiding exceptions.</p>
     *
     * <p>A negative start position can be used to start/end <code>n</code>
     * characters from the end of the String.</p>
     *
     * <p>The returned substring starts with the character in the <code>start</code>
     * position and ends before the <code>end</code> position. All position counting is
     * zero-based -- i.e., to start at the beginning of the string use
     * <code>start = 0</code>. Negative start and end positions can be used to
     * specify offsets relative to the end of the String.</p>
     *
     * <p>If <code>start</code> is not strictly to the left of <code>end</code>, ""
     * is returned.</p>
     *
     * <pre>
     * StringUtils.substring(null, *, *)    = null
     * StringUtils.substring("", * ,  *)    = "";
     * StringUtils.substring("abc", 0, 2)   = "ab"
     * StringUtils.substring("abc", 2, 0)   = ""
     * StringUtils.substring("abc", 2, 4)   = "c"
     * StringUtils.substring("abc", 4, 6)   = ""
     * StringUtils.substring("abc", 2, 2)   = ""
     * StringUtils.substring("abc", -2, -1) = "b"
     * StringUtils.substring("abc", -4, 2)  = "ab"
     * </pre>
     *
     * @param str   the String to get the substring from, may be null
     * @param start the position to start from, negative means
     *              count back from the end of the String by this many characters
     * @param end   the position to end at (exclusive), negative means
     *              count back from the end of the String by this many characters
     * @return substring from start position to end positon,
     * <code>null</code> if null String input
     */
    public static String substring(String str, int start, int end) {
        if (str == null) {
            return null;
        }

        // handle negatives
        if (end < 0) {
            end = str.length() + end; // remember end is negative
        }
        if (start < 0) {
            start = str.length() + start; // remember start is negative
        }

        // check length next
        if (end > str.length()) {
            end = str.length();
        }

        // if start is greater than end, return ""
        if (start > end) {
            return EMPTY;
        }

        if (start < 0) {
            start = 0;
        }
        if (end < 0) {
            end = 0;
        }

        return str.substring(start, end);
    }

    /**
     * start - end 替换为指定字符串
     *
     * @param str
     * @param start
     * @param end
     * @param replaceStr
     * @return
     */
    public static String replace(String str, int start, int end, String replaceStr) {
        String a = substring(str, 0, start);
        String b = substring(str, end);
        return a + replaceStr + b;
    }

    public static String join(Collection<?> collection, String separator, String leftStr, String rightStr) {
        if (collection == null) {
            return null;
        }
        if (separator == null) {
            separator = "";
        }

        int noOfItems = collection.size();
        StringBuilder buf = new StringBuilder(noOfItems * 16);

        int i = 0;
        for (Object obj : collection) {
            if (i > 0) {
                buf.append(separator);
            }
            if (leftStr != null) {
                buf.append(leftStr);
            }
            buf.append(obj);
            if (rightStr != null) {
                buf.append(rightStr);
            }
            i++;
        }
        return buf.toString();
    }

    public static String url2Path(String url, String separator) {
        if (isEmpty(url)) {
            return null;
        }

        int len = url.length();
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < len; i++) {
            char c = url.charAt(i);

            if (Character.isLetter(c)) {//字母
                buffer.append(c);
            } else {
                if (buffer.length() == 0 || i + 1 == len) {//过虑开头、结尾非字母字符
                    continue;
                }
                buffer.append(separator);
            }
        }

        return buffer.toString();
    }

    public static String getNotEmpty(String... args) {
        for (String arg : args) {
            if (arg != null && isNotBlank(arg)) {
                return arg;
            }
        }

        return null;
    }

    public static String getNotBlank(String... args) {
        for (String arg : args) {
            if (arg != null && isNotBlank(arg)) {
                return arg;
            }
        }

        return null;
    }


}
